package ltd.nullpointer.tcp.core;

import com.boot2.core.utils.ByteUtils;
import com.boot2.core.utils.RSAUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import ltd.nullpointer.tcp.core.constant.AesKeyHolder;
import ltd.nullpointer.tcp.core.message.AbstractTCPMessage;
import ltd.nullpointer.tcp.core.message.NPiotTCPMessage;
import ltd.nullpointer.tcp.core.message.EncryDecryMessage;
import ltd.nullpointer.tcp.core.message.ErrorMessage;
import ltd.nullpointer.tcp.core.util.AesUtil;

import java.util.Arrays;

/**
 * 
 * @ClassName: AbstractClientListener.java
 * @author zhangweilin
 * @date 2018年1月22日 下午4:29:00
 *
 */
public abstract class AbstractClientListener extends ChannelInboundHandlerAdapter implements AbstractHlChannelHandler {
	private transient static volatile int instanceCount = 0;

	private ChannelHandlerContext ctx;

	/**
	 * 加密类型
	 */
	private EncryType encryType;

	/**
	 * 公钥
	 */
	private String publicKey;

	/**
	 * 密钥
	 */
	private String privateKey;

	/**
	 * AES密钥
	 */
	private String aesKey;

	public AbstractClientListener() {
		if (++instanceCount > 1) {
			throw new IllegalStateException("AbstractClientListener can only has one instance");
		}
	}

	@Override
	public void send(NPiotTCPMessage npiotTCPMessage) {
		System.out.println("客户端发送等待");
		try {
			syncFuture.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		AbstractHlChannelHandler.super.send(npiotTCPMessage);
		System.out.println("客户端发送完成");
	}

	public void send(ByteBuf byteBuf) {
		try {
			syncFuture.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		getChannelHandlerContext(null).writeAndFlush(byteBuf);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		this.ctx = ctx;
		if (encryType.equals(EncryType.RSA_AES)) {
			connectWithRSA(ctx);
		} else if (encryType.equals(EncryType.AES)) {
			connectWithAES(ctx);
			// no encry
		} else {

		}
		// connectWithAES(ctx);

	}

	private void connectWithAES(ChannelHandlerContext ctx) {
		EncryDecryMessage encryDecryMessage = new EncryDecryMessage(EncryDecryMessage.KeyType.AES1);
		encryDecryMessage.setPublicKey(publicKey);
		ctx.writeAndFlush(encryDecryMessage);
	}

	private void connectWithRSA(ChannelHandlerContext ctx) throws Exception {
		EncryDecryMessage encryDecryMessage = new EncryDecryMessage(EncryDecryMessage.KeyType.RSA1);
		encryDecryMessage.setPublicKey(publicKey);
		ctx.writeAndFlush(encryDecryMessage).channel().newPromise();
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// secret key message
		if (msg instanceof EncryDecryMessage) {
			EncryDecryMessage encryDecryMessage = (EncryDecryMessage) msg;
			onMessage(ctx, encryDecryMessage);
		} else if (msg instanceof ErrorMessage) {
			ErrorMessage errorMessage = (ErrorMessage) msg;
			onErrorMessage(ctx, errorMessage);
		} else if (msg instanceof NPiotTCPMessage) {
			NPiotTCPMessage npiotMessage = (NPiotTCPMessage) msg;
			onMessage(ctx, npiotMessage);
		}

	}

	protected void onMessage(ChannelHandlerContext ctx, NPiotTCPMessage npiotMessage) {
		// TODO Auto-generated method stub

	}

	protected void onErrorMessage(ChannelHandlerContext ctx, ErrorMessage errorMessage) {

	}

	private void onMessage(ChannelHandlerContext handlerContext, EncryDecryMessage encryDecryMessage) throws Exception {
		byte[] aesKeyArr = encryDecryMessage.getPayloadByte();
		if (encryDecryMessage.getType().equals(EncryDecryMessage.KeyType.RSA2)) {
			aesKey = RSAUtil.decryptStrByPrivateKey(aesKeyArr, privateKey);
			// KeyConstant.aesKey = aesKey;
			System.out.println("RSA+AES加密，客户端持有的aes密钥: " + aesKey);
		} else if (encryDecryMessage.getType().equals(EncryDecryMessage.KeyType.AES2)) {
			System.out.println("客户端收到AESKEY数组: " + Arrays.toString(aesKeyArr));
			aesKeyArr = AesUtil.aesDecode(privateKey, aesKeyArr);
			aesKey = ByteUtils.getString(aesKeyArr);
			System.out.println("AES加密，客户端持有的aes密钥: " + aesKey);
		}
		AesKeyHolder.setAesKey(aesKey);
		syncFuture.setResponse(null);
//		System.out.println("释放锁");
		onConnected(handlerContext);
	}

	protected void onConnected(ChannelHandlerContext handlerContext) {

	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

		ctx.close();
	}

	@Override
	public Channel getChannelHandlerContext(AbstractTCPMessage abstractTCPMessage) {
		return this.ctx.channel();
	}

	public void setEncryType(EncryType encryType) {
		this.encryType = encryType;
	}

	public void setPublicKey(String publicKey) {
		this.publicKey = publicKey;
	}

	public void setPrivateKey(String privateKey) {
		this.privateKey = privateKey;
	}

}